package com.boot.common.utils;

import com.google.common.collect.Lists;
import org.springframework.beans.BeanWrapper;
import org.springframework.beans.BeanWrapperImpl;
import org.springframework.util.Assert;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

/**
 * @author Cheng JiYe
 * @description:
 * @date 2020/10/2 19:02
 */
public class BeanUtils {
    /**
     * 创建实例
     *
     * @param clazz
     * @return
     */
    public static <T> T newInstance(Class<T> clazz) {
        if (clazz == null) {
            return null;
        }
        try {
            return clazz.newInstance();
        } catch (Exception e) {
            throw new RuntimeException("New instance error!");
        }
    }

    /**
     * 拷贝对象
     *
     * @param dest 目标对象
     * @param orig 源对象
     */
    public static void copyProperties(Object dest, Object orig) {
        try {
            org.apache.commons.beanutils.BeanUtils.copyProperties(dest, orig);
        } catch (Exception e) {
            throw new RuntimeException("Copy properties error!", e);
        }
    }

    /**
     * @param source 源对象
     * @param target 目标对象
     * @Description <p> 拷贝非空对象属性值 </P>
     */
    public static void copyPropertiesIgnoreNull(Object source, Object target) {
        org.springframework.beans.BeanUtils.copyProperties(source, target, getNullPropertyNames(source));
    }

    /**
     * 将类转换为另一个类
     *
     * @param orig      源对象
     * @param destClass 目标对象Class
     * @return
     */
    public static <T> T convertBean(Object orig, Class<T> destClass) {
        Assert.notNull(destClass, "Class can't be empty!");

        if (orig == null) {
            return null;
        }

        try {
            T dest = newInstance(destClass);
            copyProperties(dest, orig);
            return dest;
        } catch (Exception e) {
            throw new RuntimeException("Convert bean error！", e);
        }
    }

    /**
     * 将类的List转换为另一个类的List
     *
     * @param origList  源对象List
     * @param destClass 目标对象Class
     */
    public static <T> List<T> convertBeanList(List<?> origList, Class<T> destClass) {
        Assert.notNull(destClass, "Class can't be empty!");


        List<T> destList = new ArrayList<>();

        if (CollectionUtils.isEmpty(origList)) {
            return Lists.newArrayList();
        } else {
            for (Object orig : origList) {
                T dest = convertBean(orig, destClass);
                destList.add(dest);
            }
        }

        return destList;
    }


    /**
     * @param source 要拷贝的对象
     * @return
     * @Description <p>获取到对象中属性为null的属性名  </P>
     */
    public static String[] getNullPropertyNames(Object source) {
        final BeanWrapper src = new BeanWrapperImpl(source);
        java.beans.PropertyDescriptor[] pds = src.getPropertyDescriptors();

        Set<String> emptyNames = new HashSet<>();
        for (java.beans.PropertyDescriptor pd : pds) {
            Object srcValue = src.getPropertyValue(pd.getName());
            if (srcValue == null) {
                emptyNames.add(pd.getName());
            }
        }
        String[] result = new String[emptyNames.size()];
        return emptyNames.toArray(result);
    }

    /**
     * 判断该对象是否: 返回ture表示所有属性为null  返回false表示不是所有属性都是null
     *
     * @param obj
     * @return
     * @throws Exception
     */
    public static boolean isAllFieldNull(Object obj) throws Exception {

        // 得到类对象
        Class stuCla = obj.getClass();

        //得到属性集合
        Field[] fs = stuCla.getDeclaredFields();
        boolean flag = true;
        for (Field f : fs) {
            //遍历属性
            // 设置属性是可以访问的(私有的也可以)
            f.setAccessible(true);
            if ("serialVersionUID".equals(f.getName())) {
                continue;
            }

            // 得到此属性的值
            Object val = f.get(obj);
            if (val != null) {
                //只要有1个属性不为空,那么就不是所有的属性值都为空
                flag = false;
                break;
            }
        }
        return flag;
    }
}
